package com.coalmine.api.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coalmine.api.domain.ApiAuth;
import com.coalmine.api.domain.ApiConfig;
import com.coalmine.api.domain.ApiToken;
import com.coalmine.api.mapper.ApiAuthMapper;
import com.coalmine.api.mapper.ApiTokenMapper;
import com.coalmine.api.service.IApiApproveService;
import com.coalmine.api.service.IApiAuthService;
import com.coalmine.api.service.IApiTokenService;
import com.coalmine.api.util.UUIDUtil;
import com.coalmine.common.constant.Constants;
import com.coalmine.common.core.redis.RedisCache;
import com.coalmine.common.utils.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * api的token信息表 服务实现类
 * </p>
 *
 * @author 尚郑
 * @since 2022-04-01
 */
@Service
@Transactional
public class ApiTokenServiceImpl extends ServiceImpl<ApiTokenMapper, ApiToken> implements IApiTokenService {


    @Autowired
    ApiAuthMapper apiAuthMapper;

    @Autowired
    ApiTokenMapper tokenMapper;

    @Autowired
    private IApiAuthService apiAuthService;

    @Autowired
    private IApiApproveService approveService;

    @Value("${datamanage.api.expire}")
    private int expire;

    @Autowired
    private RedisCache redisCache;

    /**
     * 带本地缓存的查询
     *
     * @param tokenStr
     * @return
     */
    @Override
    public ApiToken getToken(String tokenStr) {
        ApiToken token = redisCache.getCacheObject(Constants.API_TOKEN_KEY + tokenStr);
        if (token == null) {
            token = tokenMapper.selectByToken(tokenStr);
            if (token != null && token.getExpire() != null && token.getExpire() > System.currentTimeMillis()) {
                Long expire = token.getExpire() - System.currentTimeMillis();
                redisCache.setCacheObject(Constants.API_TOKEN_KEY + tokenStr, token);
                redisCache.expire(Constants.API_TOKEN_KEY + tokenStr, expire, TimeUnit.MILLISECONDS);
            }
            if (token != null && token.getExpire() == null) {
                redisCache.setCacheObject(Constants.API_TOKEN_KEY + tokenStr, token);
            }
        }
        return token;
    }

    @Override
    public int insert(ApiToken token) {
        //如果是用户名密码方式登录对密码进行加密处理
        if (StrUtil.isNotBlank(token.getPassword())) {
            long newExpire = System.currentTimeMillis() + expire * 60 * 1000;
            token.setExpire(newExpire);
            token.setPassword(DigestUtils.md5Hex(token.getPassword()));
            redisCache.setCacheObject(Constants.API_TOKEN_KEY + token.getToken(), token);
            redisCache.expire(Constants.API_TOKEN_KEY + token.getToken(), expire, TimeUnit.MINUTES);
        } else if (token.getExpire() != null && token.getExpire() > System.currentTimeMillis()) {
            Long expire = token.getExpire() - System.currentTimeMillis();
            redisCache.setCacheObject(Constants.API_TOKEN_KEY + token.getToken(), token);
            redisCache.expire(Constants.API_TOKEN_KEY + token.getToken(), expire, TimeUnit.MILLISECONDS);
        }
        if (token.getExpire() == null) {
            redisCache.setCacheObject(Constants.API_TOKEN_KEY + token.getToken(), token);
        }
        return tokenMapper.insert(token);
    }


    @Override
    public List<String> getAuthGroups(String tokenId) {
        List<String> authGroups = redisCache.getCacheObject(Constants.API_GROUP_KEY + tokenId);
        if (authGroups == null || authGroups.isEmpty()) {
            authGroups = apiAuthMapper.selectByTokenId(tokenId);
            redisCache.setCacheObject(Constants.API_GROUP_KEY + tokenId, authGroups, 4, TimeUnit.HOURS);
        }
        return authGroups;
    }

    @Override
    public List<ApiToken> getAll() {
        List<ApiToken> list = tokenMapper.getAll();
        return list;
    }

    @Override
    public int deleteById(String id) {
        ApiToken old = tokenMapper.selectById(id);
        if (!ObjectUtil.isNull(old)){
            redisCache.deleteObject(Constants.API_TOKEN_KEY + old.getToken());
            int i = tokenMapper.deleteById(id);
            i += apiAuthMapper.deleteByTokenId(id);
            return i;
        }

        return 0;
    }

    @Override
    public boolean auth(String tokenId, List<String> groupIds, String createBy) {
        int ret = apiAuthMapper.deleteByTokenId(tokenId);
//        if (ret <= 0) {
//            return false;
//        }
        if (groupIds.size() > 0) {
            List<ApiAuth> authList = new ArrayList<>();
            for (String groupId: groupIds) {
                ApiAuth auth = new ApiAuth();
                auth.setId(UUIDUtil.getUUID());
                auth.setTokenId(tokenId);
                auth.setGroupId(groupId);
                auth.setCreateBy(createBy);
                auth.setCreateTime(new Date());
                auth.setUpdateBy(createBy);
                auth.setUpdateTime(new Date());
                authList.add(auth);
            }
            boolean row = apiAuthService.saveBatch(authList);
            if (row) {
                List<String> groupIdList = apiAuthMapper.selectByTokenId(tokenId);
                redisCache.setCacheObject(Constants.API_GROUP_KEY + tokenId, groupIdList);
            }
            return row;
        } else {
            return true;
        }
    }

    /**
     * 获取token字符,通过用户名密码
     * @param name
     * @param password
     * @return
     */
    @Override
    public String getTokenByUser(String name, String password) {
        ApiToken token = getToken(name, password);
        if (token != null && token.getExpire() > System.currentTimeMillis()) {
            return token.getToken();
        } else if (token != null && token.getExpire() < System.currentTimeMillis()) {
            String newToken = DigestUtils.md5Hex(UUID.randomUUID().toString());
            token.setToken(newToken);
            long newExpire = System.currentTimeMillis() + expire * 60 * 1000;
            token.setExpire(newExpire);
            tokenMapper.updateById(token);
            //放入token缓存
            redisCache.setCacheObject(Constants.API_TOKEN_KEY + token.getToken(), token);
            redisCache.expire(Constants.API_TOKEN_KEY + token.getToken(), expire, TimeUnit.MINUTES);
            return newToken;
        } else {
            return null;
        }
    }


    /**
     * 获取toekn实体
     * @param name
     * @param password
     * @return
     */
    @Override
    public ApiToken getToken(String name, String password) {
        if (StringUtils.isNoneBlank(name) && StringUtils.isNoneBlank(password)) {
            QueryWrapper<ApiToken> tokenQueryWrapper = new QueryWrapper<ApiToken>().eq("name", name).
                    eq("password", DigestUtils.md5Hex(password));
            ApiToken token = tokenMapper.selectOne(tokenQueryWrapper);
            if (ObjectUtil.isNotNull(token)) {
                return token;
            }
        }
        return null;
    }



    @Override
    public boolean checkToken(String api, String tokenId) {
        // 检验是否token授权该资源
        String check = tokenMapper.checkToken(api,tokenId);
        // 校验是否是用户名密码
        ApiToken token = tokenMapper.selectById(tokenId);
        if (StrUtil.isNotEmpty(token.getName())){
            // 再次校验是否审批通过
             ApiConfig apiConfig = tokenMapper.getTokenByPath(api);
             if (ObjectUtil.isNotNull(apiConfig)){
                 // 查看审批表是否存在
                 String approve =  approveService.checkApprove(apiConfig.getId(),tokenId);
                 if (StrUtil.isNotEmpty(check) && StrUtil.isNotEmpty(approve)){
                     return true;
                 }
             }
             //api不存在
             return false;
        }
        // 未找到api和token信息
        if (StrUtil.isBlank(check)){
            return false;
        }
        return true;
    }

    //验证token是否过期
    @Override
    public boolean checkTokenExpire(String tokenId) {
        if(StrUtil.isNotBlank(tokenId)){
            ApiToken t = tokenMapper.selectById(tokenId);
            //获取系统当前时间
            System.currentTimeMillis();
            long timeMillis = System.currentTimeMillis();
            if(timeMillis >= t.getExpire()){
                //已过期
                return true;
            }
        }
        //未过期
        return false;
    }

    //根据id查询token
    @Override
    public ApiToken getTokenById(String tokenId) {
        ApiToken t = tokenMapper.selectById(tokenId);
        if(ObjectUtil.isNotNull(t)){
            return t;
        }
        return null;
    }

    @Override
    public int changePassword(String name, String oldPassword, String newPassword) {
        return tokenMapper.changePassword(name, oldPassword, newPassword);
    }

}
